//--------------------------------------------------------------------------------------------------  		   
// Common Deferred shadows functions
//--------------------------------------------------------------------------------------------------

#if D3D10
Texture2D DefShadowSampler : register(t3);
#endif

float4 poisson_kernel_2d[MAX_SHADOW_SAMPLES_NUM/2];

float4 CalcShadowSpace(float4 HPos)
{
  float4 P0 = HPos;
	P0.xy /= P0.w;
	P0.z *= fOneDivFarDist.x;

#if !%_RT_POINT_LIGHT
	//we do slope scale bias during shadowgen only
	//make constant bias for sun
	P0.z -= fDepthTestBias.x; 
#endif

	return P0;
}

half CalcShadow(float4 vShPos, float2 vNoisePos, int nChunk)
{
  float4 P0 = vShPos;

//clamp depth in shadows space for all FP shadowmaps
//comparison sampler doesn't do clamping internally for FP formats
#if D3D10 || %_RT_SHADOW_MIXED_MAP_G16R16
	P0.z = clamp(P0.z, 0.0f, 0.999999f);
#endif

//scale for noise projecton should be computed based on the size of shadow frustums(increase if it's bigger) 
//and distance to viewer((decrease if it's father)) 
#if %_RT_POINT_LIGHT 
	//TOFIX: compute proper scale range for point LS noise
	float2 NoiseP = P0.xy*20;
#else
	//reconstruct noise projection
	float2 NoiseP = vNoisePos.xy;
#endif

	half fInShadow = 1;


#if _RT_VARIANCE_SM
	//terrain shadows
	fInShadow = GetVarianceShadow(varianceMapSampler0, P0.xyz);
#elif %_RT_SHADOW_JITTERING
  if (GetShadowQuality()!=QUALITY_LOW)
  {
    irregular_filter(depthMapSampler0, sRotSampler, P0, NoiseP.xy, GetKernelSize(), fInShadow, nChunk);
  }
	else
	{
		//one-tap sampling
		//shadow_sample(depthMapSampler0, P0, fInShadow);
		#if !D3D10 && !_RT_HW_PCF_COMPARE
			fInShadow += fDepthShift.x;
			fInShadow = (fInShadow > P0.z);
		#endif
	}
#else 
	//debug one-tap sampling
	shadow_sample(depthMapSampler0, P0, fInShadow);
	#if !D3D10 && !_RT_HW_PCF_COMPARE
		fInShadow += fDepthShift.x;
		fInShadow = (fInShadow > P0.z);
	#endif
#endif


#ifdef %_RT_LIGHT_TEX_PROJ
 	half3 vFilterColor = tex2D(projMapSampler, P0.xy).xyz;
	half fProjectorColor = dot(vFilterColor,  half3(0.2, 0.7, 0.1));	
	//fInShadow *= fProjectorColor;
#endif

  return fInShadow;
}

#if D3D10
void irregular_filter_smpl(Texture2D depthMap, sampler2D sRotations, float4 p, float2 randDirTC, float2 kernelRadius, out float shadowTest, int nChunk = 0) //, float2 InvShadowMapWH
#else
void irregular_filter_smpl(sampler2D depthMap, sampler2D sRotations, float4 p, float2 randDirTC, float2 kernelRadius,  out half shadowTest, int nChunk = 0) //float2 InvShadowMapWH, 
#endif
{

	#define SHADOW_SAMPLES_NUM 8

  half kernelOffset = 0;
	half kernelSize = SHADOW_SAMPLES_NUM/2;

#if D3D10 && (%_RT_MSAA_QUALITY || %_RT_MSAA_QUALITY1)
  if (nChunk==0)
  {
 	  kernelSize = SHADOW_SAMPLES_NUM/8;
    kernelOffset = 0;
  }
  else
  {
 	  kernelSize = SHADOW_SAMPLES_NUM/2;
    kernelOffset = SHADOW_SAMPLES_NUM/8;
  }
#endif

	half P_Z = p.z;

  float4 p0 = float4(p.xyz,1.0f);

	half2 rotScale = kernelRadius.y * 1000.0f;

  shadowTest = 0;

	#define KERNEL_STEP_SIZE 2

	//hints the compiler to use the _bx2 modifier
#if PS3
	#pragma sce-cgc("-texformat 1 RGBA8");
#endif
	half2 rotSample = tex2D(sRotations, randDirTC.xy * rotScale.xy).xy;

#if PS3
	rotSample = rotSample * 2.h - 1.h;	// on PS3 VU16 format is unsigned
  rotSample.xy *= (kernelRadius.xy * vInvShadowMapWH.xy);

	half4 rot = half4(rotSample.x, -rotSample.y, rotSample.y, rotSample.x);

	half4 sampleDepth;
	DoubleSampleRotated(depthMap, p0, rot, irreg_kernel_2d[0], sampleDepth.xy);
	DoubleSampleRotated(depthMap, p0, rot, irreg_kernel_2d[1], sampleDepth.zw);

	half4 InShadow	= sampleDepth;
  half fInvSamplNum = (1.0 / 4.0);
  shadowTest = dot(InShadow,fInvSamplNum.xxxx);

//	DoubleSampleRotated(depthMap, p0, rot, irreg_kernel_2d[2], sampleDepth.xy);
//	DoubleSampleRotated(depthMap, p0, rot, irreg_kernel_2d[3], sampleDepth.zw);
//	InShadow	= sampleDepth;
//  shadowTest += dot(InShadow,fInvSamplNum.xxxx);
#else
  rotSample.xy *= (kernelRadius.xy * float2(1/512.0f, 1/512.0f)); //vInvShadowMapWH.xy

	//rotSample = 0.0f;

	//rotation 2x2 matrix for SampleRotated
	//float4 rot = float4(rotSample.x, rotSample.y, -rotSample.y, rotSample.x);
	//rotation 2x2 matrix for DoubleSampleRotated
	float4 rot = float4(rotSample.x, -rotSample.y, rotSample.y, rotSample.x);
  //rot *= radius * vInvShadowMapWH.xyxy;

#if D3D10
  [unroll]
#endif
	for(int i=kernelOffset; i<kernelSize; i+=KERNEL_STEP_SIZE) // Loop over taps
	{

		half4 sampleDepth;
		//SampleRotated(depthMap, p0, rot, irreg_kernel_2d[i+0].xy, sampleDepth.x);
		//SampleRotated(depthMap, p0, rot, irreg_kernel_2d[i+0].zw, sampleDepth.y);
		//SampleRotated(depthMap, p0, rot, irreg_kernel_2d[i+1].xy, sampleDepth.z);
		//SampleRotated(depthMap, p0, rot, irreg_kernel_2d[i+1].zw, sampleDepth.w);

		DoubleSampleRotated(depthMap, p0, rot, irreg_kernel_2d[i+0], sampleDepth.xy);
		DoubleSampleRotated(depthMap, p0, rot, irreg_kernel_2d[i+1], sampleDepth.zw);

		//DoubleSampleRotated(depthMap, p0, rot, irreg_kernel_2d[i+0].xy, irreg_kernel_2d[i+1].xy, sampleDepth.xy);
		//DoubleSampleRotated(depthMap, p0, rot, irreg_kernel_2d[i+2].xy, irreg_kernel_2d[i+3].xy, sampleDepth.zw);

#if D3D10		
//was for _RT_HW_PCF_COMPARE
		//FIX: flag to simulate InShadow
		#if %_RT_TEX_ARR_SAMPLE
			float4 InShadow = ( P_Z.xxxx < sampleDepth);
		#else
			float4 InShadow	= sampleDepth;
		#endif
#else
		// Determine whether tap is in shadow                
		#if _RT_HW_PCF_COMPARE 
			half4 InShadow	= sampleDepth;
		#else
			half4 InShadow = ( P_Z.xxxx < sampleDepth);
	 	 //float4 InShadow = saturate((sampleDepth-P_Z.xxxx)*10000.0f);
		#endif
#endif
    half fInvSamplNum = (1.0 / SHADOW_SAMPLES_NUM);
    shadowTest += dot(InShadow,fInvSamplNum.xxxx);
	}
//PS3
#endif
}
